﻿// This source file is part of WallpaperControl, a tool for automatic changing 
// of the desktop wallpaper.
// 
// Visit http://wpcontrol.sourceforge.net/ for more.
//
// Copyright (c) 2014 nscrolldev
//
// Licensed under the GPLv2.
// See http://www.gnu.org/licenses/gpl-2.0.html for details.
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

using System;
using System.Collections.Generic;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using System.Xml.XPath;
using System.Windows.Forms;
using System.IO;
using System.Security;

namespace WallpaperControl
{
    /// <summary>
    /// Class that manages loading and saving of the configuration files.
    /// </summary>
    class CfgFileManager
    {
        /// <summary>
        /// Saves the list of images to an XML document.
        /// </summary>
        internal void SaveImageListFile()
        {
            try
            {
                XmlDocument imgDoc = new XmlDocument();
                // Create root element
                XmlNode listNode;
                listNode = imgDoc.CreateElement("imageList");
                imgDoc.AppendChild(listNode);

                XmlNode imageNode;
                XmlNode pathNode;
                XmlNode styleNode;
                // For every single image create tag and save path and style
                for (int i = 0; i < ImageList.Instance.Images.Count; i++)
                {
                    imageNode = imgDoc.CreateElement("image");
                    listNode.AppendChild(imageNode);
                    pathNode = imgDoc.CreateElement("path");
                    pathNode.InnerText = ImageList.Instance.Images[i].Path;
                    imageNode.AppendChild(pathNode);
                    styleNode = imgDoc.CreateElement("style");
                    styleNode.InnerText = ImageList.Instance.Images[i].ZoomStyle.ToString();
                    imageNode.AppendChild(styleNode);
                }
                // Save XML document
                imgDoc.Save("images.xml");
            }
            catch (XmlException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveImgList_Xml"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveImgList_InvalidOp"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (IOException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveImgList_IO"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (SecurityException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveImgList_Security"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Loads the list of images from the XML document.
        /// </summary>
        internal void LoadImageListFile()
        {
            try
            {
                // Load config file
                XmlDocument XMLdoc = new System.Xml.XmlDocument();
                XMLdoc.Load("images.xml");
                // Get root element
                XmlElement root = XMLdoc.DocumentElement;
                // Select all images
                XmlNodeList imageNodes = root.SelectNodes("/imageList/image");
                // Add all image elements to list 
                foreach (XmlNode singleImageNode in imageNodes)
                {
                    // TODO: Unsafe to load xmlnode by its index
                    XmlNode pathNode = singleImageNode.ChildNodes.Item(0);
                    XmlNode styleNode = singleImageNode.ChildNodes.Item(1);
                    // Get path from xml
                    string path = pathNode.InnerText;
                    // Get style from xml
                    Wallpaper.Style style = (Wallpaper.Style)Enum.Parse(typeof(Wallpaper.Style), styleNode.InnerText);
                    // Add wallpaper to the list
                    ImageList.Instance.Images.Add(new Wallpaper(path, style));
                }
            }
            catch (XmlException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadImgList_Xml"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadImgList_NotFound"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (DirectoryNotFoundException)
            {
            }
            catch (PathTooLongException)
            {
            }
            catch (IOException)
            {
            }
            catch (UnauthorizedAccessException)
            {
            }
            catch (SecurityException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadImgList_Security"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (ImageFormatException)
            {
            }
            catch (WallpaperFileException)
            {
            }
            catch (ArgumentException)
            {
            }
            catch (NotSupportedException)
            {
            }
            catch (ApplicationException)
            {
                // TODO: Show MessageBox
            }
        }

        /// <summary>
        /// Saves the condition into the XML document.
        /// </summary>
        internal void SaveConditionFile()
        {
            try
            {
                // Create new config file
                XmlDocument condDoc = new XmlDocument();

                // Create root element
                XmlNode condNode;
                condNode = condDoc.CreateElement("condition");
                condDoc.AppendChild(condNode);

                // Save type of condition (numeric)
                XmlNode typeNode;
                typeNode = condDoc.CreateElement("typeID");
                typeNode.InnerText = Program.CurrentSession.ActiveCondition.Id.ToString();
                condNode.AppendChild(typeNode);

                // Save condition value
                XmlNode valueNode;
                valueNode = condDoc.CreateElement("value");
                valueNode.InnerText = Program.CurrentSession.ActiveCondition.Value.ToString();
                condNode.AppendChild(valueNode);

                // Save file
                condDoc.Save("condition.xml");
            }
            catch (XmlException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveCond_Xml"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveCond_InvalidOp"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (IOException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveCond_IO"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (SecurityException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveCond_Security"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Loads the condition from the XML document.
        /// </summary>
        internal void LoadConditionFile()
        {
            try
            {
                // Load config file in which the conditino is stored
                XmlDocument xmlDoc = new XmlDocument();
                xmlDoc.Load("condition.xml");

                // Get condition type as xml node
                XmlNode typeNode = xmlDoc.SelectSingleNode("/condition/typeID");
                // Get condition value as xml node
                XmlNode valueNode = xmlDoc.SelectSingleNode("/condition/value");

                // Get condition ID from XML
                int condId = Convert.ToInt32(typeNode.InnerText);
                // Load condition in the current session
                if (condId == CondTime.CondId)
                {
                    Program.CurrentSession.ActiveCondition = new CondTime(Convert.ToDateTime(valueNode.InnerText));
                }
                else if (condId == CondTimeInterval.CondId)
                {
                    Program.CurrentSession.ActiveCondition = new CondTimeInterval(Convert.ToInt32(valueNode.InnerText));
                }
                else if (condId == CondStartup.CondId)
                {
                    Program.CurrentSession.ActiveCondition = new CondStartup(Convert.ToInt32(valueNode.InnerText));
                }
                else if (condId == CondDayInterval.CondId)
                {
                    Program.CurrentSession.ActiveCondition = new CondDayInterval(Convert.ToInt32(valueNode.InnerText));
                }
                else
                {
                    throw new ConfigFileException("Unable to restore condition.");
                }

                // Set the value for the current condition
                Program.CurrentSession.ActiveCondition.Value = valueNode.InnerText;
            }
            catch (XmlException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadCond_Xml"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (SecurityException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadCond_Security"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (FormatException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadCond_Format"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (OverflowException)
            {
            }
            catch (UnauthorizedAccessException)
            {
                // TODO
            }
            catch (DirectoryNotFoundException)
            {
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadCond_NotFound"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (IOException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadCond_IO"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Saves the settings from the ControlPanel into a XML document.
        /// </summary>
        internal void SaveSettingsFile()
        {
            try
            {
                // Create config file storing the settings
                XmlDocument settingsDoc = new XmlDocument();
                XmlNode settingsListNode;

                // Create root element
                settingsListNode = settingsDoc.CreateElement("settings");
                settingsDoc.AppendChild(settingsListNode);

                // Create element with value for every single setting
                XmlNode settingNode;
                settingNode = settingsDoc.CreateElement("startWithSys");
                settingNode.InnerText = Program.Configuration.StartWithWindows.ToString();
                settingsListNode.AppendChild(settingNode);

                settingNode = settingsDoc.CreateElement("startControlPanel");
                settingNode.InnerText = Program.Configuration.StartWithControlPanel.ToString();
                settingsListNode.AppendChild(settingNode);

                settingNode = settingsDoc.CreateElement("changeInfo");
                settingNode.InnerText = Program.Configuration.ChangeInfo.ToString();
                settingsListNode.AppendChild(settingNode);

                settingNode = settingsDoc.CreateElement("runningInfo");
                settingNode.InnerText = Program.Configuration.RunningInfo.ToString();
                settingsListNode.AppendChild(settingNode);

                settingNode = settingsDoc.CreateElement("repeatingInfo");
                settingNode.InnerText = Program.Configuration.LoopingInfo.ToString();
                settingsListNode.AppendChild(settingNode);

                settingNode = settingsDoc.CreateElement("repeatWallpapers");
                settingNode.InnerText = Program.Configuration.LoopWallpapers.ToString();
                settingsListNode.AppendChild(settingNode);

                // Save document
                settingsDoc.Save("settings.xml");
            }
            catch (XmlException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveSettings_Xml"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveSettings_InvalidOp"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (IOException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveSettings_IO"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (SecurityException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveSettings_Security"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Loads the settings from the XML document.
        /// </summary>
        internal void LoadSettingsFile()
        {
            try
            {
                // Load config file containing the settings
                XmlDocument settingsDoc = new XmlDocument();
                settingsDoc.Load("settings.xml");

                // Select every single setting and convert it back to boolean value
                XmlNode currentNode = settingsDoc.SelectSingleNode("/settings/startWithSys");
                Program.Configuration.StartWithWindows = Convert.ToBoolean(currentNode.InnerText);

                currentNode = settingsDoc.SelectSingleNode("/settings/startControlPanel");
                Program.Configuration.StartWithControlPanel = Convert.ToBoolean(currentNode.InnerText);

                currentNode = settingsDoc.SelectSingleNode("/settings/changeInfo");
                Program.Configuration.ChangeInfo = Convert.ToBoolean(currentNode.InnerText);

                currentNode = settingsDoc.SelectSingleNode("/settings/runningInfo");
                Program.Configuration.RunningInfo = Convert.ToBoolean(currentNode.InnerText);

                currentNode = settingsDoc.SelectSingleNode("/settings/repeatingInfo");
                Program.Configuration.LoopingInfo = Convert.ToBoolean(currentNode.InnerText);

                currentNode = settingsDoc.SelectSingleNode("/settings/repeatWallpapers");
                Program.Configuration.LoopWallpapers = Convert.ToBoolean(currentNode.InnerText);
            }
            catch (XmlException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadSettings_Xml"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                Program.Configuration.LoadDefaults();
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadSettings_NotFound"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                Program.Configuration.LoadDefaults();
            }
            catch (SecurityException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadSettings_Security"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                Program.Configuration.LoadDefaults();
            }
        }

        /// <summary>
        /// Saves the current session into a XML document.
        /// </summary>
        internal void SaveSessionFile()
        {
            try
            {
                // Create new config file storing the session info
                XmlDocument sessionDoc = new XmlDocument();
                XmlNode sessionNode;

                // Create root element
                sessionNode = sessionDoc.CreateElement("session");
                sessionDoc.AppendChild(sessionNode);

                // Save session info in XML node
                XmlNode runningInfo = sessionDoc.CreateElement("running");
                runningInfo.InnerText = Program.CurrentSession.IsActive.ToString();
                sessionNode.AppendChild(runningInfo);

                XmlNode nextWallpaper = sessionDoc.CreateElement("nextWallpaper");
                nextWallpaper.InnerText = WallpaperManager.Instance.NextWallpaperIndex.ToString();
                sessionNode.AppendChild(nextWallpaper);

                XmlNode currentWallpaper = sessionDoc.CreateElement("currentWallpaper");
                currentWallpaper.InnerText = WallpaperManager.Instance.CurrentWallpaperIndex.ToString();
                sessionNode.AppendChild(currentWallpaper);

                XmlNode previousWallpaper = sessionDoc.CreateElement("previousWallpaper");
                previousWallpaper.InnerText = WallpaperManager.Instance.PreviousWallpaperIndex.ToString();
                sessionNode.AppendChild(previousWallpaper);

                /*XmlNode remainingTime = sessionDoc.CreateElement("remainingTime");
                remainingTime.InnerText = Program.ChangeClient.IntervalTimer.*/

                XmlNode changeOrder = sessionDoc.CreateElement("changeOrder");
                changeOrder.InnerText = WallpaperManager.Instance.Order.ToString();
                sessionNode.AppendChild(changeOrder);

                sessionDoc.Save("session.xml");
            }
            catch (XmlException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveSession_Xml"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (InvalidOperationException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveSession_InvalidOp"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (IOException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveSession_IO"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
            catch (SecurityException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_SaveSession_Security"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        /// <summary>
        /// Loads the details of the current session from a XML document.
        /// </summary>
        internal void LoadSessionFile()
        {
            try
            {
                // Load config file containing the session info
                XmlDocument sessionDoc = new XmlDocument();
                sessionDoc.Load("session.xml");

                // Check if session should be running
                XmlNode currentNode = sessionDoc.SelectSingleNode("session/running");
                if (Convert.ToBoolean(currentNode.InnerText))
                {
                    // Start session
                    Program.CurrentSession.Start();
                    // Update schedule 
                    if (Program.Configuration.StartWithControlPanel)
                    {
                        Program.ControlPanel.UpdateSchedule();
                    }
                }

                // Get the index of the next wallpaper
                currentNode = sessionDoc.SelectSingleNode("session/nextWallpaper");
                WallpaperManager.Instance.NextWallpaperIndex = Convert.ToInt32(currentNode.InnerText);

                // Get the index of the current wallpaper
                currentNode = sessionDoc.SelectSingleNode("session/currentWallpaper");
                WallpaperManager.Instance.CurrentWallpaperIndex = Convert.ToInt32(currentNode.InnerText);

                // Get the index of the previous wallpaper
                currentNode = sessionDoc.SelectSingleNode("session/previousWallpaper");
                WallpaperManager.Instance.PreviousWallpaperIndex = Convert.ToInt32(currentNode.InnerText);

                // Get the change mode
                currentNode = sessionDoc.SelectSingleNode("session/changeOrder");
                switch (currentNode.InnerText)
                {
                    case "Descending":
                        WallpaperManager.Instance.Order = WallpaperManager.ChangeOrder.Descending;
                        break;
                    case "Ascending":
                        WallpaperManager.Instance.Order = WallpaperManager.ChangeOrder.Ascending;
                        break;
                    case "Random":
                        WallpaperManager.Instance.Order = WallpaperManager.ChangeOrder.Random;
                        break;
                }
            }
            catch (XmlException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadSession_Xml"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                Program.Configuration.LoadDefaults();
            }
            catch (FileNotFoundException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadSession_NotFound"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                Program.Configuration.LoadDefaults();
            }
            catch (SecurityException)
            {
                MessageBox.Show(Program.Lang.GetString("Error_LoadSession_Security"), Program.Lang.GetString("Caption_Error"), MessageBoxButtons.OK, MessageBoxIcon.Error);
                Program.Configuration.LoadDefaults();
            }
        }
    }
}
